package cn.net.xyan.blossom.webUI.ui

import cn.net.xyan.blossom.kotlin.logger
import cn.net.xyan.blossom.kotlin.stackTraceMessage
import cn.net.xyan.blossom.security.service.AuthService
import cn.net.xyan.blossom.webUI.utils.notification
import com.github.vok.karibudsl.*
import com.vaadin.annotations.Theme
import com.vaadin.annotations.Viewport
import com.vaadin.event.ShortcutAction
import com.vaadin.server.VaadinRequest
import com.vaadin.spring.annotation.SpringUI
import com.vaadin.spring.server.SpringVaadinServletRequest
import com.vaadin.ui.*
import com.vaadin.ui.themes.ValoTheme
import org.apache.shiro.SecurityUtils
import org.apache.shiro.authc.*
import org.apache.shiro.web.subject.support.WebDelegatingSubject
import org.apache.shiro.web.util.WebUtils
import org.springframework.beans.factory.annotation.Autowired
import javax.servlet.ServletRequest

val jvmVersion: String get() = System.getProperty("java.version")





@SpringUI(path = "/login")
@Theme("blossom")
@Viewport("width=device-width, initial-scale=1.0")
class LoginUI : UI() {

    lateinit var bLogin: Button

    var referURL:String? = null

    @Autowired
    lateinit var authService:AuthService

    override fun init(request: VaadinRequest?) {
        page.setTitle("登陆")

        var servletRequest:ServletRequest? = null

        if (request is SpringVaadinServletRequest){
            servletRequest = request.request
        }

        referURL = request?.getHeader("Referrer")



        verticalLayout {
            setSizeFull()

            formLayout {
                addStyleName("login-form")
                caption = "请登录:"
                setSizeUndefined()
                alignment = Alignment.MIDDLE_CENTER

                val username = textField("用户名:") {
                    w = 300.px
                }

                val password = passwordField ("密码:") {
                    w = 300.px
                }

                bLogin = button("登录") {
                    addStyleName(ValoTheme.BUTTON_PRIMARY)
                    isDisableOnClick = true
                    clickShortcut = KeyShortcut(ShortcutAction.KeyCode.ENTER)

                    onLeftClick {
                        val u = username.value
                        val p = password.value

                        doLogin(u,p)
                    }
                }
            }
        }
    }

    fun doLogin(username:String,password:String){
        val token = UsernamePasswordToken(username, password)
        //获取当前的Subject
        val currentUser = SecurityUtils.getSubject()

        try {
            //在调用了login方法后,SecurityManager会收到AuthenticationToken,并将其发送给已配置的Realm执行必须的认证检查
            //每个Realm都能在必要时对提交的AuthenticationTokens作出反应
            //所以这一步在调用login(token)方法时,它会走到MyRealm.doGetAuthenticationInfo()方法中,具体验证方式详见此方法
            logger.info("对用户[$username]进行登录验证..验证开始")
            currentUser.login(token)
            logger.info("对用户[$username]进行登录验证..验证通过")
        } catch (uae: UnknownAccountException) {
            "对用户[$username]进行登录验证..验证未通过,未知账户".notification("登录失败",Notification.Type.ERROR_MESSAGE)
            //redirectAttributes.addFlashAttribute("message", "未知账户")
        } catch (ice: IncorrectCredentialsException) {
            "对用户[$username]进行登录验证..验证未通过,错误的凭证".notification("登录失败",Notification.Type.ERROR_MESSAGE)
            //redirectAttributes.addFlashAttribute("message", "密码不正确")
        } catch (lae: LockedAccountException) {
            "对用户[$username]进行登录验证..验证未通过,账户已锁定".notification("登录失败",Notification.Type.ERROR_MESSAGE)
            //redirectAttributes.addFlashAttribute("message", "账户已锁定")
        } catch (eae: ExcessiveAttemptsException) {
            "对用户[$username]进行登录验证..验证未通过,错误次数过多".notification("登录失败",Notification.Type.ERROR_MESSAGE)
            //redirectAttributes.addFlashAttribute("message", "用户名或密码错误次数过多")
        } catch (ae: AuthenticationException) {
            //通过处理Shiro的运行时AuthenticationException就可以控制用户登录失败或密码错误时的情景
            "对用户[$username]进行登录验证..验证未通过,堆栈轨迹如下\n${ae.stackTraceMessage}"
                    .notification("登录失败",Notification.Type.ERROR_MESSAGE)
        }finally {
            bLogin.isEnabled = true
        }

        //验证是否登录成功
        if (currentUser.isAuthenticated) {
            logger.info("用户[$username]登录认证通过(这里可以进行一些认证通过后的一些系统参数初始化操作)")

            if (currentUser is WebDelegatingSubject){
                val savedRequest = WebUtils.getAndClearSavedRequest(currentUser.servletRequest)
                val uri = savedRequest?.requestUrl?:"/"
                ui.page.setLocation(uri)
            }

            //return "redirect:/user"
        } else {
            token.clear()
            //return "redirect:/login"
        }
    }
}